òɾۿûѧϰʹá
ԭַhttps://www.joinquant.com/post/15815

ԭһ˵ʽ鵽ԭĺ߽ۡ


ԭĲԴ£

# ڻƵƷ֣MA˫+ٷֱ׷ֹ
# 1000000Ԫ201211ز
# 뺯
from jqdata import * 
import talib
from math import isnan

def initialize(context):
    # ò
    set_parameter(context)
    # 趨׼ڶƷֵĻز⵱л׼ûвο
    set_benchmark('511880.XSHG')
    # ̬Ȩģʽ(ʵ۸)
    set_option('use_real_price', True)
    # ˵orderϵAPIıerror͵log
    log.set_level('order', 'error')
    ### ڻ趨 ###
    # 趨˻Ϊ˻
    set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='futures')])
    # ڻÿʽʱǣʱ֮1,ʱ֮1,ƽΪ֮1
    set_order_cost(OrderCost(open_commission=0.0001, close_commission=0.0001,close_today_commission=0.0001), type='index_futures')
    # 趨֤
    set_option('futures_margin_rate', 0.15)
    # û㣨5˫ǧ1
    set_slippage(PriceRelatedSlippage(0.001),type='future')
    # ǰ
    run_daily( before_market_open, time='before_open', reference_security=get_future_code('RB'))
    # ʱ
    run_weekly(market_open, 1,time='open', reference_security=get_future_code('RB'))
#    run_monthly(market_open, 11,time='open', reference_security=get_future_code('RB'))
    #  
    #  
    run_weekly(Trade, 1, time='open', reference_security=get_future_code('RB'))
#    run_monthly(Trade, 11, time='open', reference_security=get_future_code('RB'))
    # ̺
    run_daily( after_market_close, time='after_close', reference_security=get_future_code('RB'))
    
    
    

   # ú
def set_parameter(context):
    
    ###############
    g.LastRealPrice = {} # ʵԼ۸ֵ(ڵֹ
    g.HighPrice = {} # Ʒ߼ֵ䣨ڵֹ
    g.LowPrice = {} # Ʒͼֵ䣨ڵֹ
    g.future_list = []  # ڻƷб
    g.TradeLots = {}  # ƷֵĽϢ
    g.PriceArray = {} # źż۸ֵ
    g.Price_dict = {} # Ʒּ۸бֵ
    g.Times = {} # ڷֹֹ룩
    g.Reentry_long = False # ֹ
    g.Reentry_short = False # ֹ
    g.MappingReal = {} # ʵԼӳ䣨keyΪsymbolvalueΪԼ
    g.MappingIndex = {} # ָԼӳ keyΪ symbolvalueΪָԼ
    g.StatusTimer = {} # ǰ״̬
    g.ATR = {}
    g.CurrentPrice = {}
    g.Price_DaysAgo = {}
    g.Momentum = {}
    g.ClosePrice = {}

    ###############
    g.BackWindow = 15 # ݴڳ
    g.Range = 0.3
    # ׵ڻƷϢ
    g.instruments = ['AL','NI','CU','PB','AG',
                    'RU','MA','PP','TA','L','V',
                    'M','P','Y','OI','C','CS','JD','SR',
                    'HC','J','I','SF','RB','ZC','FG']
    # ۸бʼ
    set_future_list(context)


def set_future_list(context):
    for ins in g.instruments:
        idx = get_future_code(ins)
        dom = get_dominant_future(ins)
        # ӳֵ
        g.MappingIndex[ins] = idx
        g.MappingReal[ins] = dom
        g.StatusTimer[ins] = 0
        #ԼеƷֻ
        if dom == '':
            pass
        else:
            if dom not in g.future_list:
                g.future_list.append(dom)
                g.HighPrice[dom] = False
                g.LowPrice[dom] = False
                g.Times[dom] = 0
                

'''
ģ߼insڻƷֵsymbol确RBdomfutureָԼ'RB1610.XSGE',idxָָԼ硯RB8888.XSGE
    1.ڵһ쿪ʼʱڻƷԼдMappingRealMappingIndex
    2.ÿ쿪̻ȡһinsӦԼжǷMappingRealУڣִreplaceģ
    3.replaceģУԭеԼºԼ޸MappingReal
'''
## ǰк
def before_market_open(context):
    # ʱ
    log.info('ʱ(before_market_open)'+str(context.current_dt.time()))
    send_message('ʼ')
    
    # ԼƷ֣벢޸ڻֵϢ
    for ins in g.instruments:
        dom = get_dominant_future(ins)
        if dom == '':
            pass
        else:
            # жǷִreplace_old_futures
            if dom == g.MappingReal[ins]:
                pass
            else:
                replace_old_futures(context,ins,dom)
                g.future_list.append(dom)
                g.HighPrice[dom] = False
                g.LowPrice[dom] = False
                g.Times[dom] = 0
        
            g.TradeLots[dom] = get_lots(context.portfolio.starting_cash/len(g.instruments),ins)
            

## ʱк
def market_open(context):
    # ʱ
    #log.info('ʱ(market_open):'+str(context.current_dt.time()))
    # ѭ
    for ins in g.instruments:
        # ˿ԼƷ
        if g.MappingReal[ins] != '':
            IndexFuture = g.MappingIndex[ins]
            RealFuture = g.MappingReal[ins]
            # ȡºԼ
            end_date = get_CCFX_end_date(RealFuture)
            # ºԼյ첻
            if (context.current_dt.date() == end_date):
                return
            else:
                g.LastRealPrice[RealFuture] = attribute_history(RealFuture,1,'1d',['close'])['close'][-1]
                # ȡ۸list
                #if g.StatusTimer[ins] == 0:
                g.PriceArray[IndexFuture] = attribute_history(IndexFuture,g.BackWindow+5,'1d',['close','open','high','low'])
                
                # ûݣ
                if len(g.PriceArray[IndexFuture]) < 1:
                    return
                else: 
                    g.ClosePrice[ins] = g.PriceArray[IndexFuture]['close']
                    g.CurrentPrice[ins] = g.ClosePrice[ins][-1]
                    g.Price_DaysAgo[ins] = g.ClosePrice[ins][-g.BackWindow]
                    
                    g.close = np.array(g.PriceArray[IndexFuture]['close'])
                    g.high = np.array(g.PriceArray[IndexFuture]['high'])
                    g.low = np.array(g.PriceArray[IndexFuture]['low'])
                    g.ATR[IndexFuture] = talib.ATR(g.high,g.low,g.close, g.BackWindow)[-1]
                    
                    # g.Momentum[ins] = g.CurrentPrice[ins]/g.Price_DaysAgo[ins] -1
                    g.Momentum[ins] = g.CurrentPrice[ins]/g.Price_DaysAgo[ins] -1

                    
                    
                    

           
## ̺к
def after_market_close(context):
    log.info(str('ʱ(after_market_close):'+str(context.current_dt.time())))
    # õгɽ¼
    trades = get_trades()
    for _trade in trades.values():
        log.info('ɽ¼'+str(_trade))
    log.info('һ')
    log.info('##############################################################')
    
## ģ 
def Trade(context):
    # ÿб
    log.info(g.ClosePrice.keys())
    BuyList = []
    SellList = []
    # ֵ򣬲ֵǰƷֵsymbolдб
    a = sorted(g.Momentum.items(), key=lambda x: x[1],reverse = True)
    for i in range(int(g.Range*len(g.MappingReal.keys()))):
        BuyList.append(a[i][0])
        SellList.append(a[-i-1][0])
       
        
    for ins in g.instruments:
        RealFuture = g.MappingReal[ins]
        IndexFuture = g.MappingIndex[ins]
        if RealFuture in g.LastRealPrice.keys():
            if ins in BuyList and context.portfolio.long_positions[RealFuture].total_amount == 0:
                if context.portfolio.long_positions[RealFuture].total_amount != 0:
                    log.info('ͷгֲ֣%s'%(RealFuture))
                order_target(RealFuture,0,side='short')
                order_target(RealFuture,g.TradeLots[RealFuture],side='long')
                g.HighPrice[RealFuture] = g.LastRealPrice[RealFuture]
                g.LowPrice[RealFuture] = False
                log.info('Լ%s'%(RealFuture))
        
            elif ins in SellList and context.portfolio.short_positions[RealFuture].total_amount == 0:
                if context.portfolio.short_positions[RealFuture].total_amount != 0:
                    log.info('ͷгֲ֣%s'%(RealFuture))
                order_target(RealFuture,0,side ='long')
                order_target(RealFuture,g.TradeLots[RealFuture],side='short')
                g.LowPrice[RealFuture] = g.LastRealPrice[RealFuture]
                g.HighPrice[RealFuture] = False
                log.info('պԼ%s'%(RealFuture))
            elif ins not in BuyList and RealFuture in context.portfolio.long_positions.keys():
                order_target(RealFuture,0,side ='long')
            elif ins not in SellList and RealFuture in context.portfolio.short_positions.keys():
                order_target(RealFuture,0,side ='short')
            else:
                TrailingStop(context,RealFuture,IndexFuture)
         #ģyunxi
        Dont_Re_entry(context,RealFuture,ins)     

        
        
# ׷ֹ,ֹģ
# Ϊ׷ֹڽ棬ֹҪֹϵͳٴθλ볡
def Dont_Re_entry(context,future,ins):
    # ģ飺һֹ20barڲףּ۸ͻ¼20barʧЧ
    #߼ͼۣע⣺Ҫһλ뵱ǰ۸
    if ins in g.ClosePrice.keys():
        g.Highest_high_2_20 = g.ClosePrice[ins][-21:-1].max()
        g.Lowest_low_2_20 = g.ClosePrice[ins][-21:-1].min()
    
        if  g.Reentry_long == True:
            if g.Times[future] > 20 or g.CurrentPrice[ins] > g.Highest_high_2_20 :
                g.Reentry_long = False
        if  g.Reentry_short == True:
            if g.Times[future] > 20 or g.CurrentPrice[ins] < g.Lowest_low_2_20 :
                g.Reentry_short = False
        

# ׷ֹģ飨ٷֱֹ
def TrailingStop(context,RealFuture,IndexFuture):
    
    # ¼ղλ
    long_positions = context.portfolio.long_positions
    short_positions = context.portfolio.short_positions
    
    # ͨforѭһƽ֣ͷ
    if RealFuture in long_positions.keys():
        if long_positions[RealFuture].total_amount > 0:
            if g.HighPrice[RealFuture]:
                g.HighPrice[RealFuture] = max(g.HighPrice[RealFuture], g.LastRealPrice[RealFuture])
                if g.LastRealPrice[RealFuture]  < g.HighPrice[RealFuture]-g.ATR[IndexFuture]:
                    log.info('ͷֹ:\t' +  RealFuture)
                    order_target(RealFuture,0,side = 'long')
                    g.Reentry_long = True
                    
    # ͨforѭһƽ֣ͷ
    if RealFuture in short_positions.keys():
        if short_positions[RealFuture].total_amount > 0:
            if g.LowPrice[RealFuture]:
                g.LowPrice[RealFuture] = min(g.LowPrice[RealFuture], g.LastRealPrice[RealFuture])
                if g.LastRealPrice[RealFuture]  > g.LowPrice[RealFuture]+g.ATR[IndexFuture]:
                    log.info('ͷֹ:\t' + RealFuture)
                    order_target(RealFuture,0,side = 'short')
                    g.Reentry_short = True



# Ʋģ飺Լʱƽǰֲ֣ΪԼ        
def replace_old_futures(context,ins,dom):
    
    LastFuture = g.MappingReal[ins]
    
    if LastFuture in context.portfolio.long_positions.keys():
        lots_long = context.portfolio.long_positions[LastFuture].total_amount
        order_target(LastFuture,0,side='long')
        order_target(dom,lots_long,side='long')
        print('Լƽֻ²')
    
    if LastFuture in context.portfolio.short_positions.keys():
        lots_short = context.portfolio.short_positions[dom].total_amount
        order_target(LastFuture,0,side='short')
        order_target(dom,lots_short,side='short')
        print('Լƽղֻ²')

    g.MappingReal[ins] = dom     
            
'''ɾȥԼ'''
        
        
# ȡʱڽ׵ڻԼ
def get_future_code(symbol):
    future_code_list = {'A':'A8888.XDCE', 'AG':'AG8888.XSGE', 'AL':'AL8888.XSGE', 'AU':'AU8888.XSGE',
                        'B':'B8888.XDCE', 'BB':'BB8888.XDCE', 'BU':'BU8888.XSGE', 'C':'C8888.XDCE', 
                        'CF':'CF8888.XZCE', 'CS':'CS8888.XDCE', 'CU':'CU8888.XSGE', 'ER':'ER8888.XZCE', 
                        'FB':'FB8888.XDCE', 'FG':'FG8888.XZCE', 'FU':'FU8888.XSGE', 'GN':'GN8888.XZCE', 
                        'HC':'HC8888.XSGE', 'I':'I8888.XDCE', 'IC':'IC8888.CCFX', 'IF':'IF8888.CCFX', 
                        'IH':'IH8888.CCFX', 'J':'J8888.XDCE', 'JD':'JD8888.XDCE', 'JM':'JM8888.XDCE', 
                        'JR':'JR8888.XZCE', 'L':'L8888.XDCE', 'LR':'LR8888.XZCE', 'M':'M8888.XDCE', 
                        'MA':'MA8888.XZCE', 'ME':'ME8888.XZCE', 'NI':'NI8888.XSGE', 'OI':'OI8888.XZCE', 
                        'P':'P8888.XDCE', 'PB':'PB8888.XSGE', 'PM':'PM8888.XZCE', 'PP':'PP8888.XDCE', 
                        'RB':'RB8888.XSGE', 'RI':'RI8888.XZCE', 'RM':'RM8888.XZCE', 'RO':'RO8888.XZCE', 
                        'RS':'RS8888.XZCE', 'RU':'RU8888.XSGE', 'SF':'SF8888.XZCE', 'SM':'SM8888.XZCE', 
                        'SN':'SN8888.XSGE', 'SR':'SR8888.XZCE', 'T':'T8888.CCFX', 'TA':'TA8888.XZCE', 
                        'TC':'TC8888.XZCE', 'TF':'TF8888.CCFX', 'V':'V8888.XDCE', 'WH':'WH8888.XZCE', 
                        'WR':'WR8888.XSGE', 'WS':'WS8888.XZCE', 'WT':'WT8888.XZCE', 'Y':'Y8888.XDCE', 
                        'ZC':'ZC8888.XZCE', 'ZN':'ZN8888.XSGE','AP':'AP8888.XZCE'}
    try:
        return future_code_list[symbol]
    except:
        return 'WARNING: ޴˺Լ'


# ȡATRͷ磩
def get_lots(cash,symbol):
    future_coef_list = {'A':10, 'AG':15, 'AL':5, 'AU':1000,
                        'B':10, 'BB':500, 'BU':10, 'C':10,
                        'CF':5, 'CS':10, 'CU':5, 'ER':10,
                        'FB':500, 'FG':20, 'FU':50, 'GN':10,
                        'HC':10, 'I':100, 'IC':200, 'IF':300,
                        'IH':300, 'J':100, 'JD':5, 'JM':60,
                        'JR':20, 'L':5, 'LR':10, 'M':10,
                        'MA':10, 'ME':10, 'NI':1, 'OI':10,
                        'P':10, 'PB':5, 'PM':50, 'PP':5,
                        'RB':10, 'RI':20, 'RM':10, 'RO':10,
                        'RS':10, 'RU':10, 'SF':5, 'SM':5,
                        'SN':1, 'SR':10, 'T':10000, 'TA':5,
                        'TC':100, 'TF':10000, 'V':5, 'WH':20,
                        'WR':10, 'WS':50, 'WT':10, 'Y':10,
                        'ZC':100, 'ZN':5,'AP':10}
    RealFuture = get_dominant_future(symbol)
    IndexFuture = get_future_code(symbol)
    # ȡ۸list
    Price_dict = attribute_history(IndexFuture,10,'1d',['open'])
    # ûݣ
    if len(Price_dict) == 0:
        return
    else:
        open_future = Price_dict.iloc[-1]
    # 
    if IndexFuture in g.ATR.keys():
        # ÿʹ10%ʽ𿪲ֽ
        # Լֵıʽǣg.ATR[IndexFuture]*future_coef_list[symbol]
        return cash*0.1/(g.ATR[IndexFuture]*future_coef_list[symbol])
    else:# ֮ûfutureдATRֵ䵱е
        return cash*0.0001/future_coef_list[symbol]


# # ȡ(ATR汾
# def get_lots(cash,symbol):
#     # ȡԼģ(Contract Size)Ҳƽ׵λ
#     future_Contract_Size = {'A':10, 'AG':15, 'AL':5, 'AU':1000,
#                         'B':10, 'BB':500, 'BU':10, 'C':10,
#                         'CF':5, 'CS':10, 'CU':5, 'ER':10,
#                         'FB':500, 'FG':20, 'FU':50, 'GN':10,
#                         'HC':10, 'I':100, 'IC':200, 'IF':300,
#                         'IH':300, 'J':100, 'JD':5, 'JM':60,
#                         'JR':20, 'L':5, 'LR':10, 'M':10,
#                         'MA':10, 'ME':10, 'NI':1, 'OI':10,
#                         'P':10, 'PB':5, 'PM':50, 'PP':5,
#                         'RB':10, 'RI':20, 'RM':10, 'RO':10,
#                         'RS':10, 'RU':10, 'SF':5, 'SM':5,
#                         'SN':1, 'SR':10, 'T':10000, 'TA':5,
#                         'TC':100, 'TF':10000, 'V':5, 'WH':20,
#                         'WR':10, 'WS':50, 'WT':10, 'Y':10,
#                         'ZC':100, 'ZN':5,'AP':10}
#     future = get_dominant_future(symbol)
#     # ȡ۸list
#     Price_dict = attribute_history(future,10,'1d',['open'])
#     # ûݣ
#     if len(Price_dict) == 0:
#         return
#     else:
#         # ¿̼ۣܹµ
#         open_price = Price_dict.iloc[-1]
#     # ۸*Լģ=ֵ
#     # ֤ʹã33%
#     # Լ֤ıʽǣopen_price*future_Contract_Size[symbol]*g.MarginRate
#     return cash*0.33/(open_price*future_Contract_Size[symbol]*g.MarginRate)


# ȡڻԼ
def get_CCFX_end_date(fature_code):
    # ȡڻԼ
    return get_security_info(fature_code).end_date